`timescale 1ns / 1ps

// Shift Reg
module shift_reg_rst
#(
    parameter N     = 4,
    parameter WIDTH = 1
)
(
    input   clk,
    input   rst,
    input   clken,
    
    input   [WIDTH-1: 0]    i_data,
    output  [WIDTH-1: 0]    o_data
);

localparam [WIDTH-1: 0] ZEROS = {WIDTH{1'b0}};

reg [N*WIDTH-1 : 0] sReg;
assign o_data = sReg[WIDTH-1: 0];

generate
    if (N > 1)
    begin
        always @ (posedge clk)
        begin
            if (rst) begin
                sReg <= ZEROS;
            end
            else begin
                if (clken == 1'b1)
                begin
                    sReg <= {i_data, sReg[N*WIDTH-1: WIDTH]};
                end
            end
        end
    end
    else
    begin
        always @ (posedge clk)
        begin
            if (rst) begin
                sReg <= ZEROS;
            end
            else begin
                if (clken == 1'b1)
                begin
                    sReg <= i_data;
                end
            end
        end
    end

endgenerate

endmodule

// Shift Reg without rst
module shift_reg
#(
    parameter N     = 3,
    parameter WIDTH = 8
)
(
    input   clk,
    input   clken,
    
    input   [WIDTH-1: 0]    i_data,
    output  [WIDTH-1: 0]    o_data
);

generate
    if (N != 0)
    begin
        reg [N*WIDTH-1 : 0] sReg;
        assign o_data = sReg[WIDTH-1: 0];
        if (N != 1) begin
            always @ (posedge clk)
            begin
                if (clken)
                begin
                    sReg <= {i_data, sReg[N*WIDTH-1: WIDTH]};
                end
            end
        end
        else begin
            always @ (posedge clk)
            begin
                if (clken)
                begin
                    sReg <= i_data;
                end
            end
        end
    end
    else
    begin
        assign o_data = i_data;
    end
endgenerate

endmodule

// N in --> 1 out
module PISO_SReg
#(
    parameter N     = 3,
    parameter WIDTH = 8
)
(
    input   clk,
    input   clken,
    input   ld_sh,
    
    input   [N*WIDTH-1 : 0] i_data,
    output  [WIDTH-1: 0]    o_data
);

reg [N*WIDTH-1 : 0] sReg;
assign o_data = sReg[WIDTH-1: 0];

always @ (posedge clk)
begin
    if (clken == 1'b1)
    begin
        if (ld_sh == 1'b1)  // Shift
            sReg[N*WIDTH-WIDTH-1: 0] <= sReg[N*WIDTH-1: WIDTH];
        else                // Load
            sReg <= i_data;
    end
end

endmodule

// 1 in --> N out
module SIPO_SReg
#(
    parameter N     = 3,
    parameter WIDTH = 8
)
(
    input   clk,
    input   clken, 
    
    input   [WIDTH-1: 0]    i_data,
    output  [N*WIDTH-1 : 0] o_data
);

reg [N*WIDTH-1 : 0] sReg;
assign o_data = sReg;

always @ (posedge clk)
begin
    if (clken == 1'b1)
    begin
        sReg <= {i_data, sReg[N*WIDTH-1: WIDTH]};
    end
end

endmodule

